<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 计算属性-第二版-有dirty
        let activeEffect;
        let effectStack = []
        function effect (fn, options) {
            const effectFn = () => {
                cleanup(effectFn)
                activeEffect = effectFn
                effectStack.push(effectFn)
                const res = fn()
                effectStack.pop()
                activeEffect = effectStack[effectStack.length - 1]
                return res
            }
            // 把options挂载到effectFn上
            effectFn.options = options
            effectFn.deps = []
            if (!options.lazy) {
                effectFn()
            }
            return effectFn
        } 
        function cleanup (effectFn) {
            for (let i = 0; i < effectFn.deps.length; i++) {
                const deps = effectFn.deps[i]
                deps.delete(effectFn)
            }
            effectFn.deps.length = 0
        }
        const bucket = new WeakMap()

        // 定义一个任务队列
        const jobQuene = new Set()
        // 使用Promise.resolve()创建一个promise实例，借助他，将一个任务添加到微任务队列
        const p = Promise.resolve()

        // 标志，是否正在刷新队列
        let isFlushing = false
        // 刷新函数
        function flushJob () {
            debugger
            // 如果队列正在刷新，则什么都不做
            if (isFlushing) return
            // 设置为true，代表正在刷新
            isFlushing = true
            // 在微任务队列中刷新jobQuene队列
            p.then(() => {
                debugger
                jobQuene.forEach(job => {
                    debugger
                    job()
                })
            }).finally(() => {
                isFlushing = false
            })
        }

        let temp1, temp2;
        function computed (getter) {
            // 用来缓存上一次计算的值
            let value;
            // dirty标志
            let dirty = true
            const effectFn = effect(getter, {
                lazy: true
            })

            const obj = {
                get value () {
                    // 只有dirty为脏时才计算值，并将得到的值缓存在value中
                    if (dirty) {
                        console.log('get执行了');
                        value = effectFn()
                        // 将dirty值设置为false，下一次访问只用缓存中的值
                        dirty = false
                    }
                    return value
                }
            }

            return obj
        }
        let data = {
            foo: 1,
            bar: 2
        }
        const obj = new Proxy(data, {
            get(target, key) {
                track(target, key)
                return target[key]
            },
            set(target, key, newVal) {
                target[key] = newVal
                trigger(target, key)
            }
        })
        const sumRes = computed(() => obj.foo + obj.bar)
        console.log(sumRes.value, 'sumRes.value');
        console.log(sumRes.value, 'sumRes.value');
        console.log(sumRes.value, 'sumRes.value');
        
        

        function track (target, key) {
            if (!activeEffect) return
            let depsMap = bucket.get(target)
            if (!depsMap) {
                bucket.set(target, (depsMap = new Map()))
            }
            let deps = depsMap.get(key)
            if (!deps) {
                depsMap.set(key, (deps = new Set()))
            }
            deps.add(activeEffect)
            activeEffect.deps.push(deps)
        }

        function trigger (target, key) {
            let depsMap = bucket.get(target)
            if (!depsMap) return 
            let effects = depsMap.get(key)
            const effectsToRun = new Set(effects)
            effectsToRun && effectsToRun.forEach(effectFn => {
                debugger
                if (effectFn.options.scheduler) {
                    debugger
                    effectFn.options.scheduler(effectFn)
                } else {
                    effectFn()
                }
            })
        }
    </script>
</body>
</html>